home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
os2
/
timidsrc.zip
/
dart_a.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-04-26
|
8KB
|
266 lines
/*
TiMidity -- Experimental MIDI to WAVE converter
Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
dart_c.c: This is the output driver for OS/2 DART output.
*/
#define INCL_DOSSEMAPHORES
#define INCL_DOSPROCESS
#define INCL_NOPMAPI
#define INCL_MCIOS2
#include <os2.h>
#include <os2me.h>
#include "config.h"
#include "output.h"
#include "controls.h"
#include "tables.h"
static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
static void close_output(void);
static void output_data(int32 *buf, int32 count);
static void flush_output(void);
static void purge_output(void);
/* export the playback mode */
#define dpm dart_play_mode
PlayMode dpm = {
DEFAULT_RATE, PE_16BIT|PE_SIGNED,
-1,
{40/*buffers*/,1/*dynamic priority*/,0,0,0},
"OS/2 DART output", 'd',
"",
open_output,
close_output,
output_data,
flush_output,
purge_output
};
#define PRIORTY_DELTA 30
int max_buffers,
gohigh,
offhigh;
#ifdef PM
extern HEV pausesem;
extern int paused;
extern unsigned int currtime;
extern int timeoffset;
extern HWND Frame;
#endif
LONG MyEvent (ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags);
MCI_MIX_BUFFER Buffers[100];
MCI_MIXSETUP_PARMS MixSetupParms = {NULLHANDLE,0,MCI_WAVE_FORMAT_PCM,0,0,MCI_PLAY,MCI_DEVTYPE_WAVEFORM_AUDIO,0,NULL,NULL,MyEvent,NULL,0,0};
MCI_AMP_OPEN_PARMS AmpOpenParms = {NULLHANDLE,0,0,(PSZ)MCI_DEVTYPE_AUDIO_AMPMIX,NULL,NULL,NULL};
MCI_BUFFER_PARMS BufferParms = {NULLHANDLE,sizeof(MCI_BUFFER_PARMS),0,
1 << (AUDIO_BUFFER_BITS),0,0,0,Buffers};
int buffcount=0,
numout=0,
blocking=0,
flushing=0,
hipri=0;
HEV sem;
ULONG threadID;
void s32copytos16(int32 *lp, int32 c, int16 *sp)
{
int32 l;
while (c--)
{
l=(*lp++)>>(32-16-GUARD_BITS);
if (l > 32767) l=32767;
else if (l<-32768) l=-32768;
*sp++ = (int16)(l);
}
}
void s32copytou8(int32 *lp, int32 c, uint8 *cp)
{
int32 l;
while (c--)
{
l=(*lp++)>>(32-8-GUARD_BITS);
if (l>127) l=127;
else if (l<-128) l=-128;
*cp++ = 0x80 ^ ((uint8) l);
}
}
void s32copytoulaw(int32 *lp, int32 c, uint8 *up)
{
int32 l;
while (c--)
{
l=(*lp++)>>(32-13-GUARD_BITS);
if (l > 4095) l=4095;
else if (l<-4096) l=-4096;
*up++ = _l2u[l];
}
}
LONG MyEvent (ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) {
if (ulFlags & MIX_STREAM_ERROR && ulStatus==ERROR_DEVICE_UNDERRUN) {
if (!hipri && !flushing && dpm.extra_param[1]) {
hipri=1;
DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,PRIORTY_DELTA,threadID);
}
if (flushing) {
DosPostEventSem(sem);
blocking=0;
}
}
if (ulFlags & MIX_WRITE_COMPLETE) {
#ifdef PM
/* currtime=pBuffer->ulTime+timeoffset;*/
currtime+=pBuffer->ulBufferLength;
#endif
numout--;
if (numout<gohigh && !hipri && !flushing && dpm.extra_param[1]) {
hipri=1;
DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,PRIORTY_DELTA,threadID);
}
if (blocking || (flushing && !numout)) {
DosPostEventSem(sem);
blocking=0;
}
}
return 0;
}
void error(ULONG rc) {
char errstr[80];
mciGetErrorString(rc,errstr,80);
ctl->cmsg(CMSG_ERROR,VERB_NORMAL,"MMOS/2 error: %s",errstr);
}
PTIB ptib=NULL;
static int open_output(void) {
ULONG rc;
PPIB ppib=NULL;
#ifdef PM
AmpOpenParms.hwndCallback=Frame;
#endif
rc = mciSendCommand(0,MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE_ID
#ifdef PM
| MCI_OPEN_SHAREABLE
#endif
,&AmpOpenParms,0);
if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
/* They can't mean these */
dpm.encoding&=~PE_BYTESWAP;
dpm.encoding&=~PE_ULAW;
if (dpm.encoding & PE_16BIT) dpm.encoding|=PE_SIGNED;
else dpm.encoding&=~PE_SIGNED;
MixSetupParms.ulBitsPerSample=dpm.encoding & PE_16BIT?16:8;
MixSetupParms.ulSamplesPerSec=dpm.rate;
MixSetupParms.ulChannels=dpm.encoding & PE_MONO?1:2;
rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT,&MixSetupParms,0);
if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
if (!(dpm.encoding & PE_MONO)) BufferParms.ulBufferSize*=2;
if (dpm.encoding & PE_16BIT) BufferParms.ulBufferSize*=2;
max_buffers=dpm.extra_param[0];
BufferParms.ulNumBuffers=max_buffers;
if (max_buffers<10) dpm.extra_param[1]=0;
else {
gohigh=max_buffers/4;
offhigh=max_buffers/2;
}
rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY,&BufferParms,0);
if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
DosCreateEventSem(NULL,&sem,0,TRUE);
DosGetInfoBlocks(&ptib,&ppib);
threadID=ptib->tib_ptib2->tib2_ultid;
return 0;
}
static void output_data(int32 *buf, int32 count) {
ULONG numposted;
if (numout>=max_buffers) {
DosResetEventSem(sem,&numposted);
blocking=1;
DosWaitEventSem(sem,-1);
}
if (numout>offhigh && hipri) {
hipri=0;
DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,-PRIORTY_DELTA,threadID);
}
if (!(dpm.encoding & PE_MONO)) count*=2;
if (dpm.encoding & PE_16BIT) {
s32copytos16(buf,count,Buffers[buffcount].pBuffer);
count*=2;
} else {
if (dpm.encoding & PE_ULAW)
s32toulaw(buf,count);
else s32copytou8(buf,count,Buffers[buffcount].pBuffer);
}
Buffers[buffcount].ulBufferLength=count;
/* Buffers[buffcount].ulUserParm=buffcount;*/
#ifdef PM
if (paused) DosWaitEventSem(pausesem,-1); /*Doing a mixWrite when paused causes a resume*/
#endif
MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle,&Buffers[buffcount++],1);
if (buffcount>=max_buffers) buffcount=0;
numout++;
}
static void close_output(void) {
MCI_GENERIC_PARMS GenericParms;
ULONG rc;
DosCloseEventSem(sem);
rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,&BufferParms,0);
if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_CLOSE,MCI_WAIT,&GenericParms,0);
if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
}
static void flush_output(void) {
ULONG numposted;
DosResetEventSem(sem,&numposted);
flushing=1;
if (!numout) DosPostEventSem(sem); /*Don't stop if already done*/
else
if (DosWaitEventSem(sem,6000)==640)
ctl->cmsg(CMSG_WARNING,VERB_NORMAL,"Output Flush timed out");
flushing=0;
if (hipri) {
hipri=0;
DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,-PRIORTY_DELTA,threadID);
}
}
static void purge_output (void) {
MCI_GENERIC_PARMS GenericParms;
mciSendCommand(AmpOpenParms.usDeviceID,MCI_STOP,MCI_WAIT,&GenericParms,0);
if (hipri) {
hipri=0;
DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,-PRIORTY_DELTA,threadID);
}
}